package com.twt.recruit.controller;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.twt.recruit.entity.Club;
import com.twt.recruit.entity.ClubMember;
import com.twt.recruit.entity.GroupInfo;
import com.twt.recruit.entity.User;
import com.twt.recruit.mapper.ClubMapper;
import com.twt.recruit.mapper.ClubMemberMapper;
import com.twt.recruit.mapper.GroupMapper;
import com.twt.recruit.mapper.UserMapper;
import com.twt.recruit.utils.JwtTokenUtils;
import com.twt.recruit.utils.response.CommonEnum;
import com.twt.recruit.utils.response.ResultBody;
import io.swagger.v3.oas.annotations.Operation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.zip.ZipInputStream;

@RestController
@RequestMapping("/v1")
public class ClubController {
    private final static Logger logger = LoggerFactory.getLogger(ClubController.class);

    @Resource
    ClubMapper clubMapper;

    @Resource
    UserMapper userMapper;

    @Resource
    ClubMemberMapper clubMemberMapper;

    @Resource
    GroupMapper groupMapper;

    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;




    @Operation(summary = "获取社团成员列表")
    @GetMapping("/staff/members")
    public ResultBody listClubMembers(@RequestHeader(JwtTokenUtils.TOKEN_HEADER) String token){
        Integer clubId = JwtTokenUtils.getClubHttp(token);
        LambdaQueryWrapper<ClubMember> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ClubMember::getClubId, clubId);
        JSONArray re = new JSONArray();
        List<ClubMember> clubMembers = clubMemberMapper.selectList(queryWrapper);
        if (!clubMembers.isEmpty()){
            for (ClubMember clubMember : clubMembers) {
                JSONObject t = JSONUtil.parseObj(clubMember);
                User user = userMapper.selectById(clubMember.getUid());
                t.putOpt("name", user!=null?user.getName():"");
                re.add(t);
            }
        }
        return ResultBody.success(re);
    }

    @Operation(summary = "添加社团成员")
    @PostMapping("/child/member")
    public ResultBody addClubMember(@RequestParam String uid,
                                    @RequestParam String role,
                                    @RequestHeader(JwtTokenUtils.TOKEN_HEADER) String token){
        if (uid.length()!=10){
            return ResultBody.error(CommonEnum.UID_ERROR);
        }

        String r = JwtTokenUtils.getRoleHttp(token);
        List<String> roles = Arrays.asList("ROLE_STAFF","ROLE_INTER","ROLE_CHILD","ROLE_ORGAN");
        int cr = roles.indexOf(r);
        int wr = roles.indexOf(role);
        if (wr<cr) {
            Integer clubId = JwtTokenUtils.getClubHttp(token);
            ClubMember clubMember = new ClubMember(null, clubId, uid, role, null, null);
            clubMemberMapper.insert(clubMember);
            return ResultBody.success(clubMember);
        }else {
            return ResultBody.error(CommonEnum.CLUB_ROLE_ERROR);
        }
    }


    @Operation(summary = "修改社团密码")
    @PostMapping("/organ/password")
    public ResultBody updateClubPassword(@RequestHeader(JwtTokenUtils.TOKEN_HEADER) String token,
                                         @RequestParam String origin,
                                         @RequestParam String now){
        Integer clubId = JwtTokenUtils.getClubHttp(token);
        try {
            Club club = clubMapper.selectById(clubId);
            if (!bCryptPasswordEncoder.matches(origin, club.getPassword())){
                return ResultBody.error(CommonEnum.PASSWORD_ERROR);
            }
            club.setPassword(bCryptPasswordEncoder.encode(now));
            return ResultBody.success(clubMapper.updateById(club));
        }catch (Exception e){
            logger.error("修改密码失败",e);
            return ResultBody.error("修改密码失败");
        }

    }



    @Operation(summary = "更改社团成员权限")
    @PostMapping("/organ/member/role")
    public ResultBody updateClubMember(@RequestParam Integer clubMemberId,
                                       @RequestParam String role,
                                       @RequestHeader(JwtTokenUtils.TOKEN_HEADER) String token){
        String r = JwtTokenUtils.getRoleHttp(token);
        List<String> roles = Arrays.asList("ROLE_STAFF","ROLE_INTER","ROLE_CHILD","ROLE_ORGAN");
        int cr = roles.indexOf(r);
        int wr = roles.indexOf(role);
        if (wr<cr){
            LambdaUpdateWrapper<ClubMember> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(ClubMember::getClubMemberId, clubMemberId);
            updateWrapper.set(ClubMember::getRole, role);
            clubMemberMapper.update(updateWrapper);
            return ResultBody.success(clubMemberMapper.selectById(clubMemberId));
        }else {
            return ResultBody.error(CommonEnum.CLUB_ROLE_ERROR);
        }

    }

    @Operation(summary = "删除社团成员权限")
    @PostMapping("/organ/member/out")
    public ResultBody deleteClubMember(@RequestParam Integer clubMemberId){
        return ResultBody.success(clubMemberMapper.deleteById(clubMemberId));
    }



    @Operation(summary = "批量导入社团成员")
    @PostMapping("/organ/members")
    public ResultBody importClubMember(@RequestParam MultipartFile file,
                                       @RequestHeader(JwtTokenUtils.TOKEN_HEADER) String token) {
        try {

            Integer clubId = JwtTokenUtils.getClubHttp(token);

            JSONObject re = new JSONObject();
            JSONArray success = new JSONArray();
            JSONArray failRole = new JSONArray();
            JSONArray failUid = new JSONArray();

            EasyExcel.read(file.getInputStream(), ClubMember.class, new ReadListener<ClubMember>() {
                /**
                 * 单次缓存的数据量
                 */
                public static final int BATCH_COUNT = 100;
                /**
                 * 临时存储
                 */
                private List<ClubMember> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

                @Override
                public void invoke(ClubMember data, AnalysisContext context) {
                    cachedDataList.add(data);
                    if (cachedDataList.size() >= BATCH_COUNT) {
                        saveData();
                        // 存储完成清理 list
                        cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                    }
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    saveData();
                }

                @Override
                public void onException(Exception exception, AnalysisContext context) {
                    logger.error("解析失败，但是继续解析下一行:{}", exception.getMessage());
                    // 如果是某一个单元格的转换异常 能获取到具体行号
                    // 如果要获取头的信息 配合invokeHeadMap使用
                    if (exception instanceof ExcelDataConvertException excelDataConvertException) {
                        JSONObject f = new JSONObject();
                        f.putOpt("columnIndex", excelDataConvertException.getColumnIndex());
                        f.putOpt("rowIndex", excelDataConvertException.getRowIndex());
                        f.putOpt("cellData", excelDataConvertException.getCellData().getStringValue());
                        f.putOpt("message", excelDataConvertException.getCause().getMessage());

                        failRole.add(f);
                        logger.error("第{}行，第{}列解析异常，数据为:{}", excelDataConvertException.getRowIndex(),
                                excelDataConvertException.getColumnIndex(), excelDataConvertException.getCellData().getStringValue());
                    }
                }

                /**
                 * 加上存储数据库
                 */
                private void saveData() {
                    logger.info("{}条数据，开始存储数据库", cachedDataList.size());

                    for (ClubMember clubMember : cachedDataList) {
                        String uid = clubMember.getUid();
                        LambdaQueryWrapper<ClubMember> queryWrapper = new LambdaQueryWrapper<>();
                        queryWrapper.eq(ClubMember::getClubId, clubId);
                        queryWrapper.eq(ClubMember::getUid, uid);
                        JSONObject j = new JSONObject();
                        if (userMapper.selectById(uid) == null) {
                            j.putOpt("uid", uid);
                            j.putOpt("message", "请先登录系统");
                            failUid.add(j);
                            continue;
                        }
                        if (clubMemberMapper.selectOne(queryWrapper) == null) {
                            clubMember.setClubId(clubId);
                            clubMemberMapper.insert(clubMember);
                            success.add(JSONUtil.parse(clubMember));
                        } else {
                            j.putOpt("uid", uid);
                            j.putOpt("message", "禁止重复添加");
                            failUid.add(j);
                        }

                    }
                }
            }).sheet().doRead();
            re.putOpt("success", success);
            re.putOpt("failRole", failRole);
            re.putOpt("failUid", failUid);

            return ResultBody.success(re);
        } catch (Exception e) {
            logger.error("导入失败", e);
            return ResultBody.error("导入失败");
        }
    }


    @Operation(summary = "导入社团设置组别")
    @PostMapping("/child/groups")
    public ResultBody addGroups(@RequestParam List<String> groups,
                                @RequestHeader(JwtTokenUtils.TOKEN_HEADER) String token){
        Integer clubId = JwtTokenUtils.getClubHttp(token);
        List<GroupInfo> groupInfoList = new ArrayList<>();
        for (String groupName : groups){
            GroupInfo groupInfo = new GroupInfo();
            groupInfo.setGroupName(groupName);
            groupInfo.setClubId(clubId);

            LambdaQueryWrapper<GroupInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(GroupInfo::getClubId, clubId);
            queryWrapper.eq(GroupInfo::getGroupName, groupName);
            List<GroupInfo> groupInfos = groupMapper.selectList(queryWrapper);
            if (groupInfos.isEmpty()){
                groupMapper.insert(groupInfo);
            }else {
                groupInfo.setGroupId(groupInfos.get(0).getGroupId());
            }
            groupInfoList.add(groupInfo);
        }
        return ResultBody.success(groupInfoList);
    }




    @PostMapping("/user/dist")
    @Operation(summary = "部署接口")
    public ResultBody dist(@RequestParam String key,
                           @RequestParam MultipartFile file) throws IOException {
        String path = "/var/www/recruit";
        if (Objects.equals(key, "ljc")){
            if (FileUtil.exist(path+"/dist")){
                FileUtil.del(path+"/dist");
            }
            File file1 = new File(path);
            ZipUtil.unzip(file.getInputStream(), file1, StandardCharsets.UTF_8);
            return ResultBody.success();
        }else {
            return ResultBody.error("部署失败");
        }
    }






}
